const path = require('path') //拼写路径信息
// 优化代码压缩
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
//webpack 中的所有配置信息都应该写在 module.exports 中
const { VueLoaderPlugin } = require('vue-loader');
const HTMLWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 去掉注释 去掉log 
// const TerserWebpackPlugin = require('terser-webpack-plugin');

// 将 CSS 从 JavaScript 文件中提取出来，生成独立的 CSS 文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 为模块创建了一个缓存 不兼容
// const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

// 打包性能监控插件
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 自制插件查看devServer 变化
const MyPlugin = require('./src/webpackPlugin/myPlugin')

// 显示进度条
// const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// const chalk = require('chalk');

// element plus 自动插入插件 
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')

const webpackConfig = {
    mode: 'development',
    devtool: 'eval-source-map',
    // devtool: false,
    //指定入口文件
    entry: './src/main.ts',
    //指定打包文件所在目录
    output: {
        // 加上hash值，使用哈希值可以确保在文件内容改变时，文件名也随之改变，方便浏览器缓存更新后的文件
        filename: '[name].[contenthash].js',
        //指定打包文件的目录
        path: path.resolve(__dirname, 'dist'),
        //打包后文件的文件
        environment: {
            arrowFunction: false
        },
        publicPath: '/',//表示打包后的文件在浏览器中可以通过根路径来访问
        assetModuleFilename: 'assets/[hash][ext]',//用于配置资源模块（如图片、字体等）的输出路径和文件名
    },
    cache: {
        type: 'filesystem',
        // type: "memory",
        // 选项仅当 cache.type 被设置成 'filesystem' 才可用
        cacheDirectory: path.resolve(__dirname, '.cache/webpack'),
        buildDependencies: {
            // 配置哪些依赖发生变化时需要重新构建缓存
            // webpack.config.js文件本身发生变化时，才会重新构建缓存
            config: [__filename]
        }
    },
    //指定webpack打包时使用的模块
    module: {
        //指定加载的规则
        rules: [
            {
                test: /\.vue$/,
                use: [
                    {
                        loader: 'thread-loader',
                    }, {
                        loader: 'vue-loader',
                        options: {
                            presets: ['@vue/babel-preset-jsx'],
                            cacheDirectory: true
                        }
                    }]
            },
            {
                test: /\.(js|jsx)$/,
                use: [
                    {
                        loader: 'thread-loader',
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            // 当 Webpack 解析模块之间的依赖关系时，
                            // 会将这些关系存储在cacheDirectory中。
                            // 如果下次构建时模块的依赖关系没有改变，
                            // Webpack 可以直接从缓存中获取这些信息，而不需要重新解析
                            cacheDirectory: true
                        }
                    }
                ]
            },
            {
                test: /\.(ts|tsx)$/,
                loader: 'ts-loader',
                options: {
                    configFile: path.resolve(process.cwd(), 'tsconfig.json'),
                    appendTsSuffixTo: [/\.vue$/]
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader',
                    },
                    {
                        loader: 'css-loader',
                    }
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.(jpg|jpeg)$/,
                loader: 'file-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: 'images/',
                    publicPath: 'images/'
                }
            }
        ]
    },
    //配置webpack插件
    plugins: [
        // new MyPlugin(),
        new VueLoaderPlugin(),
        // 在每次构建之前，自动清理之前构建生成的文件。
        // 这可以确保输出目录只包含最新构建的文件，
        // 避免旧文件的积累导致混乱。
        new CleanWebpackPlugin(
            {
                cleanOnceBeforeBuildPatterns: ['dist']
            }
        ),
        new webpack.DefinePlugin({
            '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': JSON.stringify(false),
        }),
        // 自动生成 HTML 文件，
        // 并将打包后的 JavaScript 和 CSS 文件自动引入到 HTML 中。
        // 它简化了 HTML 文件与 Webpack 打包输出之间的关联，
        // 确保在每次构建后，HTML 文件能够正确引用最新的打包资源。
        new HTMLWebpackPlugin({
            template: 'index.html', //相对路径
            filename: 'index.html',
        }),
        new MiniCssExtractPlugin({
            filename: 'styles.css'
        }),
        // new HardSourceWebpackPlugin()
        // new webpack.HotModuleReplacementPlugin(),
        // 打包性能监控
        // new BundleAnalyzerPlugin(),
        // 自动引入element plus
        AutoImport.default({
            resolvers: [ElementPlusResolver()],
        }),
        Components.default({
            resolvers: [ElementPlusResolver()],
        }),
        // new ProgressBarPlugin({
        //     format: 'build [:bar] :percent :elapsed seconds :msg',
        //     customTotal: 100,
        //     width: 30
        // })
    ],
    devServer: {
        static: {
            directory: path.join(__dirname, 'dist'),
            publicPath: '/'
        },
        // port: 8080,
        // liveReload: true,
        hot: true,
        // open: true,
        // webpack-dev-server会在遇到 404 错误时，自动尝试将请求重定向到index.html
        historyApiFallback: true,
    },

    // devServer: finalDevServerConfig,
    //用来设置引用模块
    resolve: {
        // 只在node_modules目录下查找模块
        modules: ['node_modules', 'src'],
        // includes:['dist'],
        // 自动补全的文件扩展名
        extensions: [
            '.ts', '.js', '.json', '.vue', '.tsx', '.css', '.sass', '.less'
        ],
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    //...其他配置
    optimization: {
        // 当这个配置应用后，在打包后的代码中，模块 ID 的分配更加稳定。
        moduleIds: 'deterministic',
        usedExports: true, // 开启标记未使用的导出成员，用于Treeshaking
        sideEffects: false,
        runtimeChunk: 'single',
        // 开启代码压缩
        minimize: true,
        // 代码分割
        splitChunks: {
            chunks: 'all',
            minSize: 29.3 * 1024,
            maxSize: 50 * 1024,
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            automaticNameDelimiter: '~',
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10
                },
                default: {
                    minChunks: 2,
                    priority: -20,
                    reuseExistingChunk: true
                }
            }
        },
        minimizer: [
            new TerserPlugin({
                // 设置需要进行压缩优化的文件范围，这里可以是正则表达式等，示例为匹配所有.js文件
                test: /\.js$/,
                // 设置包含的文件范围，可省略，若设置则需符合特定格式，这里示例为包含src目录下所有文件
                include: /src/,
                // 设置排除的文件范围，可省略，若设置则需符合特定格式，这里示例为排除node_modules目录下所有文件
                exclude: /node_modules/,
                // 设置terser的具体压缩选项，这里可以根据需求详细设置，比如压缩等级等
                terserOptions: {
                    // 去除警告信息
                    warnings: false,
                    compress: {
                        warnings: false,
                        // 去掉console.log
                        drop_console: true,
                        // 去除debug
                        drop_debugger: true,
                    }
                },
                // 是否提取注释，可设置为布尔值或对象以进行更精细的设置，这里示例为提取注释
                extractComments: false,
                // 是否启用并行压缩，可设置为布尔值，这里示例为启用并行压缩
                parallel: true,
                // 是否进行压缩操作，可设置为布尔值，这里示例为进行压缩操作
                // minify: (file, sourceMap) => {
                //     // 自定义minify函数
                //     const terser = require('terser');
                //     return terser.minify(file, {
                //         // 这里是传递给terser.minify的参数，如sourceMap等
                //         sourceMap: sourceMap
                //     });
                // },
            }),
            // new TerserWebpackPlugin({
            //     terserOptions: {
            //         compress: {
            //             drop_console: true, // 去掉console.log语句
            //             pure_funcs: ['console.log'], // 另一种去掉console.log的方式，可以和上面的选项配合使用
            //             warnings: false, // 关闭压缩过程中的警告信息
            //             dead_code: true, // 去除无用代码，可用于去掉注释等
            //         },
            //         output: {
            //             comments: false, // 去掉输出文件中的注释
            //         }
            //     }
            // })
        ]
    },
}

module.exports = webpackConfig
